package com.autonavi.yunda.yunji.controller;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.common.exception.AmapPreconditions;
import com.autonavi.yunda.yunji.configuration.exception.ResourceNotFoundException;
import com.autonavi.yunda.yunji.controller.response.ScriptResponse;
import com.autonavi.yunda.yunji.core.engine.Engine;
import com.autonavi.yunda.yunji.core.engine.script.FunctionScriptClassManager;
import com.autonavi.yunda.yunji.core.engine.script.InterfaceScriptClass;
import com.autonavi.yunda.yunji.core.engine.script.ScriptClassManager;
import com.autonavi.yunda.yunji.core.model.dto.InterfaceConfigDTO;
import com.autonavi.yunda.yunji.core.service.InterfaceConfigService;
import com.autonavi.yunda.yunji.core.vo.HttpRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author cizhong.wcs
 * @date 2022/3/7 8:50 下午
 */
@Slf4j
@RestController
public class ApiController {
    @Value("${yunji.init.interface.lazy:false}")
    private Boolean lazyInit;
    @Autowired
    private Engine engine;
    @Autowired
    private ScriptClassManager scriptClassManager;
    @Autowired
    private InterfaceConfigService interfaceConfigService;
    @Autowired
    private FunctionScriptClassManager functionScriptClassManager;

    @RequestMapping("/**")
    public Object rest(HttpServletRequest request, HttpServletResponse response) {
        InterfaceScriptClass scriptClass = scriptClassManager.fetchScriptClassByUriFromCache(request.getRequestURI());
        if (scriptClass == null && lazyInit) {
            scriptClassManager.refreshScriptClassCacheByUri(request.getRequestURI());
            scriptClass = scriptClassManager.fetchScriptClassByUriFromCache(request.getRequestURI());
        }
        if (scriptClass == null) {
            throw new ResourceNotFoundException();
        }
        return engine.exeApi(scriptClass, new HttpRequest(request, scriptClass.engineData.fetchStartNode().contentType), response);
    }

    @RequestMapping(value = "_yunji/common/api")
    public void api(HttpServletRequest request, HttpServletResponse response) {
        String uri = request.getParameter("uri");
        AmapPreconditions.checkArgumentForUser(StringUtils.isNotBlank(uri), "uri不能为空");
        if (!uri.startsWith("/")) {
            uri = "/" + uri;
        }
        try {
            InterfaceScriptClass scriptClass = scriptClassManager.fetchScriptClassByUriFromCache(uri);
            if (scriptClass == null) {
                throw new ResourceNotFoundException();
            }
            if (!scriptClass.exposedByRestapi) {
                log.warn("interface is not exposedByRestapi uri = {}", uri);
                throw new ResourceNotFoundException();
            }
            RequestDispatcher requestDispatcher = request.getRequestDispatcher(uri);
            requestDispatcher.forward(request, response);
        } catch (ResourceNotFoundException e) {
            throw e;
        } catch (Exception e) {
            log.error("yunji-common-api forward error. uri:{}", uri, e);
            throw new AmapException(AmapExceptionCode.COMMON_SERVER_ERROR, e);
        }
    }


    @GetMapping(path = {"/_fetchCurrentValidScript"})
    public ScriptResponse fetchCurrentValidScript(String uri) {
        InterfaceScriptClass interfaceScriptClass = scriptClassManager.fetchScriptClassByUriFromCache(uri);
        if (interfaceScriptClass != null) {
            return ScriptResponse.fromScriptClass(interfaceScriptClass);
        }
        return null;
    }

    @GetMapping(path = {"/_refreshScriptClassCache"})
    public void refreshScriptClassCache(Long id) {
        InterfaceConfigDTO dto = interfaceConfigService.findByIdOrThrow(id);
        scriptClassManager.refreshScriptClassCacheByUri(dto.getUri());
    }

    @GetMapping(path = {"/_refreshFunctionCache"})
    public void refreshFunctionCache(String name, String version) {
        functionScriptClassManager.refreshFunctionCacheByNameVersion(name, version);
    }
}
